package com.cencat.order.controller;

import com.cencat.common.annotation.Log;
import com.cencat.common.core.controller.BaseController;
import com.cencat.common.core.domain.AjaxResult;
import com.cencat.common.core.page.TableDataInfo;
import com.cencat.common.enums.BusinessType;
import com.cencat.common.utils.poi.ExcelUtil;
import com.cencat.order.domain.DispatchOrder;
import com.cencat.order.domain.DispatchRule;
import com.cencat.order.domain.DispatchTask;
import com.cencat.order.domain.vo.DispatchVO;
import com.cencat.order.domain.vo.DispatchStatisticsVO;
import com.cencat.order.domain.vo.DispatchMonitorVO;
import com.cencat.order.domain.dto.DispatchCreateDTO;
import com.cencat.order.domain.dto.DispatchUpdateDTO;
import com.cencat.order.domain.dto.DispatchRuleDTO;
import com.cencat.order.domain.dto.DispatchTaskDTO;
import com.cencat.order.service.IDispatchService;
import com.cencat.order.service.IDispatchRuleService;
import com.cencat.order.service.IDispatchTaskService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * 智能派单系统控制器
 * 
 * @author cencat
 * @date 2024-01-20
 */
@Tag(name = "智能派单管理", description = "智能派单系统核心功能接口")
@RestController
@RequestMapping("/dispatch")
@RequiredArgsConstructor
@Validated
public class DispatchController extends BaseController {

    private final IDispatchService dispatchService;
    private final IDispatchRuleService dispatchRuleService;
    private final IDispatchTaskService dispatchTaskService;

    /**
     * 智能派单
     */
    @Operation(summary = "智能派单", description = "基于AI算法进行智能派单")
    @PreAuthorize("@ss.hasPermi('dispatch:create')")
    @Log(title = "智能派单", businessType = BusinessType.INSERT)
    @PostMapping("/intelligent")
    public AjaxResult intelligentDispatch(@Valid @RequestBody DispatchCreateDTO createDTO) {
        DispatchVO dispatchVO = dispatchService.intelligentDispatch(createDTO);
        return success(dispatchVO);
    }

    /**
     * 手动派单
     */
    @Operation(summary = "手动派单", description = "管理员手动指定司机派单")
    @PreAuthorize("@ss.hasPermi('dispatch:create')")
    @Log(title = "手动派单", businessType = BusinessType.INSERT)
    @PostMapping("/manual")
    public AjaxResult manualDispatch(@RequestParam Long orderId,
                                    @RequestParam Long driverId,
                                    @RequestParam(required = false) String remark) {
        DispatchVO dispatchVO = dispatchService.manualDispatch(orderId, driverId, remark);
        return success(dispatchVO);
    }

    /**
     * 批量派单
     */
    @Operation(summary = "批量派单", description = "批量处理多个订单派单")
    @PreAuthorize("@ss.hasPermi('dispatch:batch')")
    @Log(title = "批量派单", businessType = BusinessType.INSERT)
    @PostMapping("/batch")
    public AjaxResult batchDispatch(@RequestParam Long[] orderIds,
                                   @RequestParam(required = false) String dispatchStrategy) {
        List<DispatchVO> results = dispatchService.batchDispatch(orderIds, dispatchStrategy);
        return success(results);
    }

    /**
     * 重新派单
     */
    @Operation(summary = "重新派单", description = "对已派单订单重新分配司机")
    @PreAuthorize("@ss.hasPermi('dispatch:reassign')")
    @Log(title = "重新派单", businessType = BusinessType.UPDATE)
    @PostMapping("/reassign")
    public AjaxResult reassignDispatch(@RequestParam Long dispatchId,
                                      @RequestParam(required = false) Long newDriverId,
                                      @RequestParam String reason) {
        DispatchVO dispatchVO = dispatchService.reassignDispatch(dispatchId, newDriverId, reason);
        return success(dispatchVO);
    }

    /**
     * 取消派单
     */
    @Operation(summary = "取消派单", description = "取消已派发的订单")
    @PreAuthorize("@ss.hasPermi('dispatch:cancel')")
    @Log(title = "取消派单", businessType = BusinessType.UPDATE)
    @PostMapping("/cancel")
    public AjaxResult cancelDispatch(@RequestParam Long dispatchId,
                                    @RequestParam String reason) {
        boolean result = dispatchService.cancelDispatch(dispatchId, reason);
        return toAjax(result);
    }

    /**
     * 查询派单列表
     */
    @Operation(summary = "查询派单列表", description = "分页查询派单信息")
    @PreAuthorize("@ss.hasPermi('dispatch:list')")
    @GetMapping("/list")
    public TableDataInfo list(DispatchOrder dispatchOrder) {
        startPage();
        List<DispatchOrder> list = dispatchService.selectDispatchList(dispatchOrder);
        return getDataTable(list);
    }

    /**
     * 获取派单详情
     */
    @Operation(summary = "获取派单详情", description = "根据派单ID获取详细信息")
    @PreAuthorize("@ss.hasPermi('dispatch:query')")
    @GetMapping(value = "/{dispatchId}")
    public AjaxResult getInfo(@Parameter(description = "派单ID") @PathVariable Long dispatchId) {
        DispatchVO dispatchVO = dispatchService.getDispatchDetail(dispatchId);
        return success(dispatchVO);
    }

    /**
     * 更新派单状态
     */
    @Operation(summary = "更新派单状态", description = "更新派单的执行状态")
    @PreAuthorize("@ss.hasPermi('dispatch:update')")
    @Log(title = "派单管理", businessType = BusinessType.UPDATE)
    @PutMapping("/status")
    public AjaxResult updateStatus(@RequestParam Long dispatchId,
                                  @RequestParam String status,
                                  @RequestParam(required = false) String remark) {
        boolean result = dispatchService.updateDispatchStatus(dispatchId, status, remark);
        return toAjax(result);
    }

    /**
     * 司机接单
     */
    @Operation(summary = "司机接单", description = "司机确认接受派单")
    @PostMapping("/accept")
    public AjaxResult acceptDispatch(@RequestParam Long dispatchId,
                                    @RequestParam Long driverId) {
        boolean result = dispatchService.acceptDispatch(dispatchId, driverId);
        return toAjax(result);
    }

    /**
     * 司机拒单
     */
    @Operation(summary = "司机拒单", description = "司机拒绝接受派单")
    @PostMapping("/reject")
    public AjaxResult rejectDispatch(@RequestParam Long dispatchId,
                                    @RequestParam Long driverId,
                                    @RequestParam String reason) {
        boolean result = dispatchService.rejectDispatch(dispatchId, driverId, reason);
        return toAjax(result);
    }

    /**
     * 获取待派单订单
     */
    @Operation(summary = "待派单订单", description = "获取等待派单的订单列表")
    @PreAuthorize("@ss.hasPermi('dispatch:query')")
    @GetMapping("/pending-orders")
    public AjaxResult getPendingOrders(@RequestParam(required = false) String priority,
                                      @RequestParam(required = false) String region) {
        List<Map<String, Object>> orders = dispatchService.getPendingOrders(priority, region);
        return success(orders);
    }

    /**
     * 获取可用司机列表
     */
    @Operation(summary = "可用司机列表", description = "获取当前可派单的司机列表")
    @PreAuthorize("@ss.hasPermi('dispatch:query')")
    @GetMapping("/available-drivers")
    public AjaxResult getAvailableDrivers(@RequestParam(required = false) Double longitude,
                                         @RequestParam(required = false) Double latitude,
                                         @RequestParam(required = false) Double radius) {
        List<Map<String, Object>> drivers = dispatchService.getAvailableDrivers(longitude, latitude, radius);
        return success(drivers);
    }

    /**
     * 派单规则管理
     */
    @Operation(summary = "查询派单规则", description = "获取派单规则列表")
    @PreAuthorize("@ss.hasPermi('dispatch:rule:list')")
    @GetMapping("/rules")
    public TableDataInfo getRules(DispatchRule dispatchRule) {
        startPage();
        List<DispatchRule> list = dispatchRuleService.selectRuleList(dispatchRule);
        return getDataTable(list);
    }

    /**
     * 新增派单规则
     */
    @Operation(summary = "新增派单规则", description = "创建新的派单规则")
    @PreAuthorize("@ss.hasPermi('dispatch:rule:add')")
    @Log(title = "派单规则", businessType = BusinessType.INSERT)
    @PostMapping("/rule")
    public AjaxResult addRule(@Valid @RequestBody DispatchRuleDTO ruleDTO) {
        DispatchRule rule = dispatchRuleService.createRule(ruleDTO);
        return success("新增成功", rule.getId());
    }

    /**
     * 修改派单规则
     */
    @Operation(summary = "修改派单规则", description = "更新派单规则配置")
    @PreAuthorize("@ss.hasPermi('dispatch:rule:edit')")
    @Log(title = "派单规则", businessType = BusinessType.UPDATE)
    @PutMapping("/rule")
    public AjaxResult editRule(@Valid @RequestBody DispatchRuleDTO ruleDTO) {
        boolean result = dispatchRuleService.updateRule(ruleDTO);
        return toAjax(result);
    }

    /**
     * 删除派单规则
     */
    @Operation(summary = "删除派单规则", description = "删除指定派单规则")
    @PreAuthorize("@ss.hasPermi('dispatch:rule:remove')")
    @Log(title = "派单规则", businessType = BusinessType.DELETE)
    @DeleteMapping("/rule/{ruleIds}")
    public AjaxResult removeRule(@Parameter(description = "规则ID数组") @PathVariable Long[] ruleIds) {
        boolean result = dispatchRuleService.deleteRuleByIds(ruleIds);
        return toAjax(result);
    }

    /**
     * 启用/禁用派单规则
     */
    @Operation(summary = "启用禁用规则", description = "启用或禁用派单规则")
    @PreAuthorize("@ss.hasPermi('dispatch:rule:edit')")
    @Log(title = "派单规则", businessType = BusinessType.UPDATE)
    @PutMapping("/rule/status")
    public AjaxResult changeRuleStatus(@RequestParam Long ruleId, @RequestParam String status) {
        boolean result = dispatchRuleService.updateRuleStatus(ruleId, status);
        return toAjax(result);
    }

    /**
     * 派单任务管理
     */
    @Operation(summary = "查询派单任务", description = "获取派单任务列表")
    @PreAuthorize("@ss.hasPermi('dispatch:task:list')")
    @GetMapping("/tasks")
    public TableDataInfo getTasks(DispatchTask dispatchTask) {
        startPage();
        List<DispatchTask> list = dispatchTaskService.selectTaskList(dispatchTask);
        return getDataTable(list);
    }

    /**
     * 创建派单任务
     */
    @Operation(summary = "创建派单任务", description = "创建定时派单任务")
    @PreAuthorize("@ss.hasPermi('dispatch:task:add')")
    @Log(title = "派单任务", businessType = BusinessType.INSERT)
    @PostMapping("/task")
    public AjaxResult createTask(@Valid @RequestBody DispatchTaskDTO taskDTO) {
        DispatchTask task = dispatchTaskService.createTask(taskDTO);
        return success("创建成功", task.getId());
    }

    /**
     * 执行派单任务
     */
    @Operation(summary = "执行派单任务", description = "手动执行指定派单任务")
    @PreAuthorize("@ss.hasPermi('dispatch:task:execute')")
    @Log(title = "派单任务", businessType = BusinessType.UPDATE)
    @PostMapping("/task/execute/{taskId}")
    public AjaxResult executeTask(@Parameter(description = "任务ID") @PathVariable Long taskId) {
        boolean result = dispatchTaskService.executeTask(taskId);
        return toAjax(result);
    }

    /**
     * 停止派单任务
     */
    @Operation(summary = "停止派单任务", description = "停止正在执行的派单任务")
    @PreAuthorize("@ss.hasPermi('dispatch:task:stop')")
    @Log(title = "派单任务", businessType = BusinessType.UPDATE)
    @PostMapping("/task/stop/{taskId}")
    public AjaxResult stopTask(@Parameter(description = "任务ID") @PathVariable Long taskId) {
        boolean result = dispatchTaskService.stopTask(taskId);
        return toAjax(result);
    }

    /**
     * 派单统计信息
     */
    @Operation(summary = "派单统计", description = "获取派单统计数据")
    @PreAuthorize("@ss.hasPermi('dispatch:statistics')")
    @GetMapping("/statistics")
    public AjaxResult getStatistics(@RequestParam(required = false) String startDate,
                                   @RequestParam(required = false) String endDate,
                                   @RequestParam(required = false) String dimension) {
        DispatchStatisticsVO statistics = dispatchService.getDispatchStatistics(startDate, endDate, dimension);
        return success(statistics);
    }

    /**
     * 派单效率分析
     */
    @Operation(summary = "效率分析", description = "分析派单效率和成功率")
    @PreAuthorize("@ss.hasPermi('dispatch:analyze')")
    @GetMapping("/efficiency-analysis")
    public AjaxResult getEfficiencyAnalysis(@RequestParam(required = false) String startDate,
                                           @RequestParam(required = false) String endDate,
                                           @RequestParam(required = false) String groupBy) {
        Map<String, Object> analysis = dispatchService.getEfficiencyAnalysis(startDate, endDate, groupBy);
        return success(analysis);
    }

    /**
     * 派单实时监控
     */
    @Operation(summary = "实时监控", description = "获取派单系统实时监控数据")
    @PreAuthorize("@ss.hasPermi('dispatch:monitor')")
    @GetMapping("/monitor")
    public AjaxResult getMonitorData() {
        DispatchMonitorVO monitorData = dispatchService.getMonitorData();
        return success(monitorData);
    }

    /**
     * 派单异常处理
     */
    @Operation(summary = "异常处理", description = "处理派单过程中的异常情况")
    @PreAuthorize("@ss.hasPermi('dispatch:exception')")
    @Log(title = "派单异常", businessType = BusinessType.UPDATE)
    @PostMapping("/handle-exception")
    public AjaxResult handleException(@RequestParam Long dispatchId,
                                     @RequestParam String exceptionType,
                                     @RequestParam String solution,
                                     @RequestParam(required = false) String remark) {
        boolean result = dispatchService.handleException(dispatchId, exceptionType, solution, remark);
        return toAjax(result);
    }

    /**
     * 获取异常派单列表
     */
    @Operation(summary = "异常派单列表", description = "获取存在异常的派单列表")
    @PreAuthorize("@ss.hasPermi('dispatch:exception:list')")
    @GetMapping("/exceptions")
    public TableDataInfo getExceptions(@RequestParam(required = false) String exceptionType,
                                      @RequestParam(required = false) String status) {
        startPage();
        List<Map<String, Object>> list = dispatchService.getExceptionDispatches(exceptionType, status);
        return getDataTable(list);
    }

    /**
     * 派单预警设置
     */
    @Operation(summary = "预警设置", description = "设置派单系统预警规则")
    @PreAuthorize("@ss.hasPermi('dispatch:alert')")
    @Log(title = "派单预警", businessType = BusinessType.UPDATE)
    @PostMapping("/alert-rule")
    public AjaxResult setAlertRule(@RequestParam String alertType,
                                  @RequestParam String condition,
                                  @RequestParam String threshold,
                                  @RequestParam(required = false) String notifyUsers) {
        boolean result = dispatchService.setAlertRule(alertType, condition, threshold, notifyUsers);
        return toAjax(result);
    }

    /**
     * 派单数据导出
     */
    @Operation(summary = "导出派单数据", description = "导出派单信息到Excel")
    @PreAuthorize("@ss.hasPermi('dispatch:export')")
    @Log(title = "派单管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, DispatchOrder dispatchOrder) {
        List<DispatchOrder> list = dispatchService.selectDispatchList(dispatchOrder);
        ExcelUtil<DispatchOrder> util = new ExcelUtil<DispatchOrder>(DispatchOrder.class);
        util.exportExcel(response, list, "派单数据");
    }

    /**
     * 派单数据导入
     */
    @Operation(summary = "导入派单数据", description = "从Excel导入派单信息")
    @PreAuthorize("@ss.hasPermi('dispatch:import')")
    @Log(title = "派单管理", businessType = BusinessType.IMPORT)
    @PostMapping("/import")
    public AjaxResult importData(MultipartFile file) throws Exception {
        ExcelUtil<DispatchOrder> util = new ExcelUtil<DispatchOrder>(DispatchOrder.class);
        List<DispatchOrder> dispatchList = util.importExcel(file.getInputStream());
        String message = dispatchService.importDispatches(dispatchList);
        return success(message);
    }

    /**
     * 智能推荐司机
     */
    @Operation(summary = "智能推荐司机", description = "基于AI算法推荐最适合的司机")
    @PreAuthorize("@ss.hasPermi('dispatch:recommend')")
    @PostMapping("/recommend-driver")
    public AjaxResult recommendDriver(@RequestParam Long orderId,
                                     @RequestParam(required = false) Integer topN) {
        List<Map<String, Object>> recommendations = dispatchService.recommendDriver(orderId, topN);
        return success(recommendations);
    }

    /**
     * 派单策略配置
     */
    @Operation(summary = "策略配置", description = "配置派单策略参数")
    @PreAuthorize("@ss.hasPermi('dispatch:strategy')")
    @Log(title = "派单策略", businessType = BusinessType.UPDATE)
    @PostMapping("/strategy")
    public AjaxResult configureStrategy(@RequestParam String strategyType,
                                       @RequestBody Map<String, Object> strategyParams) {
        boolean result = dispatchService.configureStrategy(strategyType, strategyParams);
        return toAjax(result);
    }

    /**
     * 获取派单策略
     */
    @Operation(summary = "获取策略配置", description = "获取当前派单策略配置")
    @PreAuthorize("@ss.hasPermi('dispatch:strategy:query')")
    @GetMapping("/strategy")
    public AjaxResult getStrategy(@RequestParam(required = false) String strategyType) {
        Map<String, Object> strategy = dispatchService.getStrategy(strategyType);
        return success(strategy);
    }

    /**
     * 派单性能优化
     */
    @Operation(summary = "性能优化", description = "优化派单系统性能")
    @PreAuthorize("@ss.hasPermi('dispatch:optimize')")
    @Log(title = "派单优化", businessType = BusinessType.UPDATE)
    @PostMapping("/optimize")
    public AjaxResult optimizePerformance(@RequestParam(required = false) String optimizeType) {
        Map<String, Object> result = dispatchService.optimizePerformance(optimizeType);
        return success(result);
    }

    /**
     * 批量更新派单状态
     */
    @Operation(summary = "批量更新状态", description = "批量更新多个派单的状态")
    @PreAuthorize("@ss.hasPermi('dispatch:batch:update')")
    @Log(title = "派单管理", businessType = BusinessType.UPDATE)
    @PutMapping("/batch-status")
    public AjaxResult batchUpdateStatus(@RequestParam Long[] dispatchIds,
                                       @RequestParam String status,
                                       @RequestParam(required = false) String remark) {
        boolean result = dispatchService.batchUpdateStatus(dispatchIds, status, remark);
        return toAjax(result);
    }

    /**
     * 派单回滚
     */
    @Operation(summary = "派单回滚", description = "回滚错误的派单操作")
    @PreAuthorize("@ss.hasPermi('dispatch:rollback')")
    @Log(title = "派单回滚", businessType = BusinessType.UPDATE)
    @PostMapping("/rollback")
    public AjaxResult rollbackDispatch(@RequestParam Long dispatchId,
                                      @RequestParam String reason) {
        boolean result = dispatchService.rollbackDispatch(dispatchId, reason);
        return toAjax(result);
    }
}